/*
 *  vec3.h
 *  Ray Tracer
 *  Basic functions and struct to represent 3d vectors.
 *
 *  Created by Chirantan Ekbote on 9/9/10.
 *  Copyright 2010 Ohio State University. All rights reserved.
 *
 */

#ifndef _VEC3_H_
#define _VEC3_H_

#ifdef  __cplusplus
extern "C" {
#endif	// __cplusplus
	
#include <math.h>
#include <stdlib.h>

typedef struct vec3 {
	float x;
	float y;
	float z;
} vec3;

static inline vec3 makeVec3(const float x, const float y, const float z) {
	vec3 temp = {x, y, z};
	return temp;
}

static inline vec3 vec3Neg(const vec3 v) {
	vec3 temp = {-v.x, -v.y, -v.z};
	return temp;
}

// Same as square root of dot product
static inline float vec3Length(const vec3 v) {
	return sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
}

static inline float vec3SquaredLength(const vec3 v) {
	return v.x*v.x + v.y*v.y + v.z*v.z;
}

static inline vec3 vec3Add(const vec3 v1, const vec3 v2) {
	vec3 temp = {v1.x + v2.x, v1.y + v2.y, v1.z + v2.z};
	return temp;
}

static inline vec3 vec3Sub(const vec3 v1, const vec3 v2) {
	vec3 temp = {v1.x - v2.x, v1.y - v2.y, v1.z - v2.z};
	return temp;
}

static inline vec3 vec3Mul(const vec3 v, const float f) {
	vec3 temp = {v.x * f, v.y * f, v.z * f};
	return temp;
}

static inline vec3 vec3Div(const vec3 v, const float f) {
	float div = 1.0f / f;
	vec3 temp = {v.x * div, v.y * div, v.z * div};
	return temp;
}

static inline float vec3Dot(const vec3 v1, const vec3 v2) {
	return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
}

static inline vec3 vec3Cross(const vec3 v1, const vec3 v2) {
	// Middle term has minus sign for determinant incorporated into it
	vec3 temp = {v1.y*v2.z - v1.z*v2.y,
				 v1.z*v2.x - v1.x*v2.z,
				 v1.x*v2.y - v1.y*v2.x};
	return temp;
}
	
	
static inline vec3 vec3UnitVector(const vec3 v) {
	return vec3Div(v, vec3Length(v));
}
	
	
static inline vec3 vec3Jitter(const vec3 r, const vec3 u, const vec3 v, const vec3 n, 
							  float width, float height) {
	// jitter = r - width/2*u - height/2*v + du*width*u + dv*height*v
	return vec3Add(vec3Sub(vec3Sub(r, vec3Mul(u, width*0.5f)), 
						   vec3Mul(v, height*0.5f)), 
				   vec3Add(vec3Mul(u, width * (rand() / (float)RAND_MAX)), 
						   vec3Mul(v, height * (rand() / (float)RAND_MAX))));
}
	

static inline float vec3TripleProduct(const vec3 v1, const vec3 v2, const vec3 v3) {
	return vec3Dot(vec3Cross(v1, v2), v3);
}

static inline int vec3Equal(const vec3 v1, const vec3 v2) {
	return (v1.x==v2.x && v1.y==v2.y && v1.z==v2.z);
}

static inline float vec3MinComponent(const vec3 v) {
	float temp = v.x;
	if (v.y < temp) { temp = v.y; }
	if (v.z < temp) { temp = v.z; }
	return temp;
}

static inline float vec3MaxComponent(const vec3 v) {
	float temp = v.x;
	if (v.y > temp) { temp = v.y; }
	if (v.z > temp) { temp = v.z; }
	return temp;
}

static inline float vec3MinAbsComponent(const vec3 v) {
	float temp = fabs(v.x);
	if (fabs(v.y) < temp) { temp = fabs(v.y); }
	if (fabs(v.z) < temp) { temp = fabs(v.z); }
	return temp;
}

static inline float vec3MaxAbsComponent(const vec3 v) {
	float temp = fabs(v.x);
	if (fabs(v.y) > temp) { temp = fabs(v.y); }
	if (fabs(v.z) > temp) { temp = fabs(v.z); }
	return temp;
}

#ifdef  __cplusplus
}
#endif	// __cplusplus
#endif // _VEC_3_H_